package com.ys.多线程.p7Locks实现生产者与消费者线程同步;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 描述: 店员是一个共享资源,可以为生产者和消费者服务,但是不能同时服务两者
 *
 * condition.await();    Condition  的类的锁方法 改进了一下 await
 *
 *
 * @author CodeYang
 * @version 2021/1/5 19:49
 */
public class Clerk {

    /**
     * 模拟餐台:-1 表示餐台默认为空,- 生产者-生产,消费者 wait 等待
     */
    private int product = -1;

    /**
     * 定义一个公平锁
     */
    private Lock lck = new ReentrantLock(true);

    /**
     * 创建锁的条件对象
     */
    private Condition condition = lck.newCondition();


    /**
     * 消费者调用该方法,从餐台拿走产品
     * @return
     */
    public int getProduct() throws Exception {
        lck.lock();
        try {
            // 表示:餐台为空 ,登台 生产者 生产产品
            while (this.product == -1){
               // wait();
                condition.await();
            }
            // 餐台不为空 ,拿走产品, 餐台又为空
            int tempProduct = product;
            product = -1;
            // 唤醒所有线程.唤醒 生产者线程
           // notifyAll();  == signalAll
            condition.signalAll();
            // 这里方法不结束, 其他线程还是在moniotr状态中,只有整个 方法结束,其他的线程才被唤醒
            System.out.println("消费者成功消费了"+tempProduct+"个产品");
            return tempProduct;
        }finally {
            lck.unlock();
        }





    }

    /**
     * 生产者调用该方法,生成产品到餐台
     * @param product
     */
    public void setProduct(int product) throws  Exception{

      lck.lock();
      try {
          // 证明餐台非空,不需要生产,进入等待通知状态
          while (this.product !=-1){
              //wait();
              condition.await();
          }
          // 证明餐台已经空,需要生产
          // 生产者将产品放入餐台
          this.product = product;
          // 通知消费者拿走产品
          //notifyAll();
          condition.signalAll();
          // notifyAll 执行之后将 消费者线程唤醒到 montior 状态,
          System.out.println("生产者生产了"+this.product+"个产品");

      }finally {
          lck.unlock();
      }

      // Lock 对象没有 monitor 这个状态,因为 没有这个字节码
        /**
         * ​	Condition对象有三个重要方法aWait()方法、signal()方法、signalAll()方法
         *
         * ​		aWait()相当于Object类的wait()
         *
         * ​		signal()相当于Object类的notify()
         *
         * ​		signalAll()相当于Object类的notifyAll()
         * Lock对wait()和notifyAll()方法不友好，有莫名其妙的bug，所以使用Lock完成多线程协作最好配合Condition对象一起使用
         */

    }
}
